package com.wentao.thisService.service.impl;

import com.aliyuncs.exceptions.ClientException;
import com.wentao.thisFacade.common.UserInfo;
import com.wentao.thisFacade.common.enums.ConstString;
import com.wentao.thisFacade.common.enums.ExceptionCode;
import com.wentao.thisFacade.common.enums.business.LoginStatusEnum;
import com.wentao.thisFacade.common.enums.business.RequestModeCode;
import com.wentao.thisFacade.common.enums.business.UserLockStatusEnum;
import com.wentao.thisFacade.common.enums.business.ValidStatusEnum;
import com.wentao.thisFacade.common.exception.CustomException;
import com.wentao.thisFacade.domain.reqeust.ForgetPasswordRequest;
import com.wentao.thisFacade.domain.reqeust.MobileAndCodeRequest;
import com.wentao.thisFacade.domain.reqeust.MobileCodeRequest;
import com.wentao.thisFacade.domain.reqeust.VerificationCodeRequest;
import com.wentao.thisFacade.domain.result.SmsResult;
import com.wentao.thisService.common.CommonFunction;
import com.wentao.thisService.common.SmsRunner;
import com.wentao.thisService.common.redis.RedisExecutor;
import com.wentao.thisService.mapper.CommonDao;
import com.wentao.thisService.mapper.UserDao;
import com.wentao.thisService.model.UserEntity;
import com.wentao.thisService.service.AuthenticationService;
import com.wentao.thisService.service.CacheUserService;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.sql.Timestamp;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;

/**
 * @Auther: ZhaiYanTao
 * @Date: 2020/3/27 10:16
 * @Description: 验证，授权 service实现
 */
@Service
public class AuthenticationServiceImpl implements AuthenticationService {

    @Autowired
    private RedisExecutor redisExecutor;

    @Autowired
    private CacheUserService cacheUserService;

    @Autowired
    private UserDao userDao;

    @Autowired
    private SmsRunner smsRunner;

    @Autowired
    private CommonDao commonDao;

    /**
     * @see AuthenticationService#login(String, String, String)
     */
    @Override
    public UserInfo login(String userName, String password, String loginSystem) {
        Timestamp nowTimestamp = commonDao.getNowTime();
        long nowTime = nowTimestamp.getTime();

        if (StringUtils.isBlank(userName)) {
            throw new CustomException(ExceptionCode.USERNAME_IS_NULL);
        }
        if (StringUtils.isBlank(password)) {
            throw new CustomException(ExceptionCode.PASSWORD_IS_NULL);
        }

        String passwordMD5 = CommonFunction.CreateMd5(password);

        Map<String, UserInfo> userInfoCache = cacheUserService.getAllUserInfoCache();

        if (null == userInfoCache || userInfoCache.size() == 0) {
            // TODO: 2020/3/28 缓存异常，拉取数据到缓存一次
            userInfoCache = new HashMap<>();
            if (!userInfoCache.containsKey(userName)) {

            }
        }

        UserInfo userInfo = userInfoCache.get(userName);
        if (UserLockStatusEnum.LOCK.getCode().equals(userInfo.getLockStatus())) {
            throw new CustomException(ExceptionCode.USER_LOCK);
        }
        if (!(passwordMD5.equals(userInfo.getPassword()))) {
            throw new CustomException(ExceptionCode.PASSWORD_ERROR);
        }

        // 刷新登录状态
        String token = UUID.randomUUID().toString();
        userInfo.setLoginStatus(LoginStatusEnum.login.getCode());
        userInfo.setToken(token);
        userInfo.setLastLoginTime(nowTime);
        cacheUserService.putToUserInfoCache(userInfo);

        return userInfo;
    }

    /**
     * @see AuthenticationService#mobileCodeGain(MobileCodeRequest)
     */
    @Override
    public Boolean mobileCodeGain(MobileCodeRequest mobileCodeRequest) throws Exception {
        SmsResult smsResult = getVerificationCodeByMobile(mobileCodeRequest);

        String smsSuccessMsg = "OK";
        return smsSuccessMsg.equals(smsResult.getMessage());
    }

    /**
     * @see AuthenticationService#mobileAndCodeLogin(MobileAndCodeRequest)
     */
    @Override
    public UserInfo mobileAndCodeLogin(MobileAndCodeRequest mobileAndCodeRequest) {
        boolean checkFlag = mobileVerificationCodeCheck(mobileAndCodeRequest.getMobile(), mobileAndCodeRequest.getCode());
        if (!checkFlag) {
            throw new CustomException(ExceptionCode.VERIFICATION_CODE_ERROR);
        }

        Timestamp nowTimestamp = commonDao.getNowTime();
        long nowTime = nowTimestamp.getTime();

        Map<String, UserInfo> userInfoCache = cacheUserService.getAllUserInfoCache();

        if (null == userInfoCache || userInfoCache.size() == 0) {
            // TODO: 2020/3/28 缓存异常，拉取数据到缓存一次
            userInfoCache = new HashMap<>();
            if (!userInfoCache.containsKey(mobileAndCodeRequest.getMobile())) {

            }
        }

        UserInfo userInfo = userInfoCache.get(mobileAndCodeRequest.getMobile());
        if (UserLockStatusEnum.LOCK.getCode().equals(userInfo.getLockStatus())) {
            throw new CustomException(ExceptionCode.USER_LOCK);
        }

        // 刷新登录状态
        String token = UUID.randomUUID().toString();
        userInfo.setLoginStatus(LoginStatusEnum.login.getCode());
        userInfo.setToken(token);
        userInfo.setLastLoginTime(nowTime);
        cacheUserService.putToUserInfoCache(userInfo);

        return userInfo;
    }

    /**
     * @see AuthenticationService#loginByUserNameAndToken(String, String)
     */
    @Override
    public UserInfo loginByUserNameAndToken(String userName, String token) {
        long nowTime = commonDao.getNowTime().getTime();

        Map<String, UserInfo> userInfoCache = cacheUserService.getAllUserInfoCache();

        if (null == userInfoCache || userInfoCache.size() == 0) {
            // TODO: 2020/3/28 缓存异常，拉取数据到缓存一次
            userInfoCache = new HashMap<>();
            if (!userInfoCache.containsKey(userName)) {

            }
        }

        UserInfo userInfo = userInfoCache.get(userName);
        if (UserLockStatusEnum.LOCK.getCode().equals(userInfo.getLockStatus())) {
            throw new CustomException(ExceptionCode.USER_LOCK);
        }
        if (LoginStatusEnum.login_out.getCode().equals(userInfo.getLockStatus())
                || nowTime - userInfo.getLastLoginTime() > 7 * 24 * 60 * 60 * 1000) {
            userInfo.setToken(null);
            throw new CustomException(ExceptionCode.TOKEN_EXPIRE_ERROR);
        } else {
            if (!token.equals(userInfo.getToken())) {
                throw new CustomException(ExceptionCode.TOKEN_NOTMATCH_ERROR);
            }
            // 刷新登录状态
            userInfo.setLoginStatus(LoginStatusEnum.login.getCode());
            userInfo.setToken(token);
            userInfo.setLastLoginTime(nowTime);
            cacheUserService.putToUserInfoCache(userInfo);
        }

        return userInfo;
    }

    /**
     * @see AuthenticationService#changePassword(ForgetPasswordRequest)
     */
    @Override
    public Boolean changePassword(ForgetPasswordRequest forgetPasswordRequest) {
        // 验证码验证
        boolean checkFlag = mobileVerificationCodeCheck(forgetPasswordRequest.getMobile(), forgetPasswordRequest.getCode());
        if (!checkFlag) {
            throw new CustomException(ExceptionCode.VERIFICATION_CODE_ERROR);
        }

        // 用户信息
        UserEntity searchUser = new UserEntity();
        searchUser.setMobile(forgetPasswordRequest.getMobile());
        List<UserEntity> userEntityList = userDao.Search(searchUser);
        if (null == userEntityList || userEntityList.size() == 0) {
            throw new CustomException(ExceptionCode.USER_NOT_EXIST);
        }
        searchUser = userEntityList.get(0);

        // 更新密码
        String password = CommonFunction.CreateMd5(forgetPasswordRequest.getPassword());
        searchUser.setPassword(password);
        userDao.UpdateById(searchUser);

        // 用户退出登录
        UserInfo deleteUserFromCache = new UserInfo();
        deleteUserFromCache.setUserName(forgetPasswordRequest.getMobile());
        cacheUserService.deleteUserInfoCache(deleteUserFromCache);

        return true;
    }

    /**
     * @see AuthenticationService#loginOut(String)
     */
    @Override
    public Boolean loginOut(String userName) {
        // 用户退出登录
        UserInfo deleteUserFromCache = new UserInfo();
        deleteUserFromCache.setUserName(userName);
        cacheUserService.deleteUserInfoCache(deleteUserFromCache);

        return true;
    }

    /**
     * @see AuthenticationService#checkLogin(Long, String)
     */
    @Override
    public boolean checkLogin(Long userId, String token) throws Exception {
        UserEntity searchUser = new UserEntity();
        searchUser.setId(userId);
        searchUser.setStatus(ValidStatusEnum.VALID.getCode());
        List<UserEntity> userEntityList = userDao.Search(searchUser);
        searchUser = userEntityList.get(0);

        UserInfo userInfo = loginByUserNameAndToken(searchUser.getUserName(), token);

        return null == userInfo;
    }

    /**
     * @see AuthenticationService#mobileVerificationCodeCheck(String, String)
     */
    @Override
    public boolean mobileVerificationCodeCheck(String mobile, String code) {
        String redisValue = RedisExecutor.getStr(ConstString.MOBILE_LOGIN, mobile);
        if (null == redisValue || "".equals(redisValue)) {
            throw new CustomException(ExceptionCode.SYSTEM_ERROR);
        }
        return redisValue.equals(code);
    }

    /**
     * 手机号获取验证码
     *
     * @param mobileCodeRequest 手机号 + 验证码类型
     * @return 发送结果code和message
     * @throws ClientException 阿里云短信服务异常
     */
    private SmsResult getVerificationCodeByMobile(MobileCodeRequest mobileCodeRequest) throws ClientException {
        VerificationCodeRequest verificationCodeRequest = new VerificationCodeRequest();
        verificationCodeRequest.setCode(CommonFunction.CreateRandomNumer(6));
        String requestMode = mobileCodeRequest.getRequestMode();
        SmsResult smsResult;

        String templateCode;
        if (RequestModeCode.LOGIN_IN_CODE.getCode().equals(requestMode)) {
            //登录获取验证码
            templateCode = "SMS_182681050";
        } else if (RequestModeCode.REGISTER_TO_CODE.getCode().equals(requestMode)) {
            //注册获取验证码
            templateCode = "SMS_182667520";
        } else {
            //忘记密码获取验证码
            templateCode = "SMS_182895659";
        }

        // 请求阿里云
        smsResult = smsRunner.sendSms(mobileCodeRequest.getMobile(), templateCode, verificationCodeRequest);
        if ("OK".equals(smsResult.getMessage())) {
            // 存redis
            redisExecutor.addString(ConstString.MOBILE_LOGIN, mobileCodeRequest.getMobile(), verificationCodeRequest.getCode());
            redisExecutor.setExpireMinutes(mobileCodeRequest.getMobile(), 5);
            // TODO: 2020/3/28 是否需要修改缓存的形式，用cacheservice还是redisExecutor ？修改的话需要连校验验证码方法一起修改
        }

        return smsResult;
    }

}
